package com.settlement.system.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.settlement.system.common.constant.SystemConstants;
import com.settlement.system.common.enums.DeleteEnum;
import com.settlement.system.common.enums.NoMatchRecordStatusEnum;
import com.settlement.system.common.enums.WebHookEnum;
import com.settlement.system.common.model.QyWechatData;
import com.settlement.system.common.util.HttpUtils;
import com.settlement.system.common.util.StringUtils;
import com.settlement.system.handler.disruptor.MessageVo;
import com.settlement.system.mapper.DataMapper;
import com.settlement.system.mapper.NoMatchRecordMapper;
import com.settlement.system.mapper.OmsOrderLinkMapper;
import com.settlement.system.mapper.SysPlatformIdLinkMapper;
import com.settlement.system.model.entity.NoMatchRecord;
import com.settlement.system.model.entity.OmsOrderLink;
import com.settlement.system.model.entity.SysPlatformIdLink;
import com.settlement.system.model.entity.WebHook;
import com.settlement.system.service.PlatformSourceDataService;
import com.settlement.system.service.WebHookService;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
@RequiredArgsConstructor
public class PlatformSourceDataServiceImpl implements PlatformSourceDataService {

    private static final Logger logger = LoggerFactory.getLogger(PlatformSourceDataServiceImpl.class);
    private final DataMapper dataMapper;

    private final SysPlatformIdLinkMapper sysPlatformIdLinkMapper;

    private final OmsOrderLinkMapper omsOrderLinkMapper;

    private final WebHookService webhookService;

    private final NoMatchRecordMapper noMatchRecordMapper;

    @Override
    public Map<String, Object> getDataByTableNameAndId(String tablePrefix, String dataId) {
        return dataMapper.getDataById(tablePrefix, dataId);
    }

    @Override
    public boolean existDataByTableNameAndId(String tablePrefix, String dataId) {
        return Objects.nonNull(this.getDataByTableNameAndId(tablePrefix, dataId)) && !this.getDataByTableNameAndId(tablePrefix, dataId).isEmpty();
    }

    @Override
    public List<Map<String, Object>> getDataBySql(String sql, String tableName) {
        if (StringUtils.hasText(dataMapper.existTable(tableName))) {
            return dataMapper.getDataBySql(sql);
        }
        return new ArrayList<>();
    }

    @Override
    public List<SysPlatformIdLink> getSubNoListByMainNo(String sourcePreformMainNo) {
        int lastYear = 2024;
        List<Integer> yearList = new ArrayList<>();
        int year = LocalDate.now().getYear();
        while (year >= lastYear) {
            yearList.add(year);
            year--;
        }
        List<SysPlatformIdLink> resultList = new ArrayList<>();
        List<SysPlatformIdLink> queryList;
        SysPlatformIdLink query;
        String tableName;
        for (Integer yearInt : yearList) {
            tableName = "sys_platform_id_link_%s".formatted(yearInt);
            if (!StringUtils.hasText(sysPlatformIdLinkMapper.existTable(tableName))) {
                continue;
            }
            query = new SysPlatformIdLink();
            query.setTableName(tableName);
            query.setMainNo(sourcePreformMainNo);
            queryList = sysPlatformIdLinkMapper.getList(query);
            if (queryList.size() > 0) {
                resultList.addAll(queryList);
            }
        }
        return resultList;
    }

    @Override
    public void saveOmsLink(String linkNo, String mainNoStr, String subNoStr, String tableId) {
        int year = LocalDate.now().getYear();
        String tableName = "oms_order_link_%s".formatted(year);
        if (!StringUtils.hasText(omsOrderLinkMapper.existTable(tableName))) {
            omsOrderLinkMapper.createTable(tableName);
        }
        OmsOrderLink omsOrderLink;
        for (String mainNo : mainNoStr.strip().split(",")) {
            for (String subNo : subNoStr.strip().split(",")) {
                omsOrderLink = new OmsOrderLink();
                omsOrderLink.setLinkNo(linkNo);
                omsOrderLink.setMainNo(mainNo);
                omsOrderLink.setSubNo(subNo);
                omsOrderLink.setTableId(tableId);
                omsOrderLink.setTableName(tableName);
                try {
                    omsOrderLinkMapper.insertData(omsOrderLink);
                } catch (Exception ignore) {
                }
            }
        }
    }

    @Override
    public List<String> getLinkList(String linkNo, String mainNo, String subNo) {
        List<String> omsOrderIdList = new ArrayList<>();
        int lastYear = 2024;
        List<Integer> yearList = new ArrayList<>();
        int year = LocalDate.now().getYear();
        while (year >= lastYear) {
            yearList.add(year);
            year--;
        }
        String tableName;
        OmsOrderLink query;
        List<OmsOrderLink> linkList;
        for (Integer yearInt : yearList) {
            tableName = "oms_order_link_%s".formatted(yearInt);
            if (!StringUtils.hasText(omsOrderLinkMapper.existTable(tableName))) {
                continue;
            }
            query = new OmsOrderLink();
            query.setTableName(tableName);
            query.setLinkNo(linkNo);
            query.setMainNo(mainNo);
            query.setSubNo(subNo);
            linkList = omsOrderLinkMapper.getList(query);
            if (linkList.size() > 0) {
                for (OmsOrderLink omsOrderLink : linkList) {
                    if (!omsOrderIdList.contains(omsOrderLink.getTableId())) {
                        omsOrderIdList.add(omsOrderLink.getTableId());
                    }
                }
            }
        }
        return omsOrderIdList;
    }

    @Override
    public Map<String, String> checkImportFileTitle(Set<String> importFileTitleList, Map<String, String> keyMap) {
        Map<String, String> messageMap = new HashMap<>();
        List<String> newImportFileTitleList = new ArrayList<>();
        for (String title : importFileTitleList) {
            newImportFileTitleList.add(title.replaceAll("\uFEFF", "").strip());
        }
        List<String> stringSet = keyMap.keySet().stream().filter(item -> !Objects.equals(item, "店铺ID") && !Objects.equals(item, "原商户订单号")).toList();
        // 差集 (importFileTitleList - stringSet)
        List<String> reduce1 = newImportFileTitleList.stream().filter(item -> !stringSet.contains(item)).toList();
        if (reduce1.size() > 0) {
            messageMap.put("导入表格有，系统没有", String.join(",", reduce1));
        }
        // 差集 (stringSet - importFileTitleList)
        List<String> reduce2 = stringSet.stream().filter(item -> !newImportFileTitleList.contains(item)).toList();
        if (reduce2.size() > 0) {
            messageMap.put("系统有，导入表格没有", String.join(",", reduce2));
        }
        return messageMap;
    }

    @Override
    public void sendMessage(String platform, String storeName, String orderType, String message, MultipartFile file) {
        List<WebHook> webHooks = webhookService.list(new LambdaQueryWrapper<WebHook>().eq(WebHook::getStatus, WebHookEnum.ENABLE.getValue()));
        String content = "嗨玩够RPA提醒：\n平台：<font color=\"warning\">%s</font> 店铺：<font color=\"warning\">%s</font>，导入失败。\n"
                .formatted(platform, storeName) +
                "单据类型：<font color=\"comment\">%s</font>\n".formatted(orderType) +
                "错误信息：<font color=\"comment\">%s</font>\n".formatted(message) +
                "<font color=\"warning\">请立即查看</font>\n";
        QyWechatData qyWechatData = new QyWechatData(content);
        String wediaId = null;
        if (Objects.nonNull(file) && webHooks.size() > 0) {
            // 切除key
            String webhookKey = webHooks.get(0).getWebHookUrl().split("key=")[1].strip();
            // 获取文件的大小，以M为单位
            long fileSize = file.getSize() / 1024 / 1024;
            if (fileSize <= 20) {
                // 上传文件
                try {
                    String postUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key=%s&type=file".formatted(webhookKey);
                    ResponseEntity<String> result = HttpUtils.uploadFile(file.getOriginalFilename(), file, fileSize, postUrl);
                    logger.info("上传文件结果：{}", result);
                    JSONObject jsonObject = JSONObject.parseObject(result.getBody());
                    if (Objects.nonNull(jsonObject) && Objects.nonNull(jsonObject.getString("media_id"))) {
                        wediaId = jsonObject.getString("media_id");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        for (WebHook webHook : webHooks) {
            if (SystemConstants.WECHAT.equals(webHook.getHookType())) {
                HttpUtils.sendToQyWechat(qyWechatData, webHook.getWebHookUrl());
                if (Objects.nonNull(wediaId)) {
                    // 发送文件
                    qyWechatData = new QyWechatData("file", wediaId);
                    logger.info("推送文件ID：{}", wediaId);
                    HttpUtils.sendToQyWechat(qyWechatData, webHook.getWebHookUrl());
                }
            }
        }
    }

    @Override
    public void sendMessage(String platform, String storeName, String orderType, String message) {
        List<WebHook> webHooks = webhookService.list();
        String content = "嗨玩够RPA提醒：\n平台：<font color=\"warning\">%s</font> 店铺：<font color=\"warning\">%s</font>，导入失败。\n"
                .formatted(platform, storeName) +
                "单据类型：<font color=\"comment\">%s</font>\n".formatted(orderType) +
                "错误信息：<font color=\"comment\">%s</font>\n".formatted(message) +
                "<font color=\"warning\">请立即查看</font>\n";
        QyWechatData qyWechatData = new QyWechatData(content);
        for (WebHook webHook : webHooks) {
            if (SystemConstants.WECHAT.equals(webHook.getHookType()) && Objects.equals(WebHookEnum.ENABLE.getValue(), webHook.getStatus())) {
                HttpUtils.sendToQyWechat(qyWechatData, webHook.getWebHookUrl());
            }
        }
    }

    @Override
    public OmsOrderLink getOmsLinkRecordByOrderNo(String orderNo) {
        int lastYear = 2024;
        List<Integer> yearList = new ArrayList<>();
        int year = LocalDate.now().getYear();
        while (year >= lastYear) {
            yearList.add(year);
            year--;
        }
        String tableName;
        OmsOrderLink query;
        List<OmsOrderLink> linkList;
        for (Integer yearInt : yearList) {
            tableName = "oms_order_link_%s".formatted(yearInt);
            if (!StringUtils.hasText(omsOrderLinkMapper.existTable(tableName))) {
                continue;
            }
            query = new OmsOrderLink();
            query.setTableName(tableName);
            query.setLinkNo(orderNo);
            linkList = omsOrderLinkMapper.getList(query);
            if (linkList.size() > 0) {
                return linkList.get(0);
            }
        }
        return null;
    }

    @Override
    public void addNoMatchRecord(MessageVo messageVo, String billType, String remark) {
        NoMatchRecord noMatchRecord = new NoMatchRecord();
        BeanUtils.copyProperties(messageVo, noMatchRecord);
        noMatchRecord.setBillType(billType);
        noMatchRecord.setUpdateTime(LocalDateTime.now());
        noMatchRecord.setStatus(NoMatchRecordStatusEnum.ERROR.getValue());
        noMatchRecord.setTableNamePreFix(messageVo.getTableNamePrefix());
        List<NoMatchRecord> recordList = noMatchRecordMapper.selectList(new LambdaQueryWrapper<NoMatchRecord>().eq(NoMatchRecord::getDataId, messageVo.getDataId()).eq(NoMatchRecord::getStoreId, messageVo.getStoreId()).eq(NoMatchRecord::getDeleted, DeleteEnum.NO.getValue()));
        logger.info("正在插入或者更新一条转换失败记录：{}", messageVo);
        if (recordList.size() == 0) {
            logger.info("根据dataId【%s】没有找到转换失败的记录...".formatted(messageVo.getDataId()));
            if (StringUtils.hasText(remark)) {
                noMatchRecord.setRemark("【%s】没有找到账单配置，转换标准账单失败，原因：【%s】".formatted(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), remark));
            } else {
                noMatchRecord.setRemark("【%s】没有找到账单配置，转换标准账单失败".formatted(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
            }
            noMatchRecord.cutString();
            noMatchRecordMapper.insert(noMatchRecord);
            logger.info("插入转换失败记录成功...");
        } else {
            for (NoMatchRecord matchRecord : recordList) {
                logger.info("正在更新转换失败记录：{}", matchRecord.toString());
                matchRecord.setStatus(NoMatchRecordStatusEnum.ERROR.getValue());
                if (StringUtils.hasText(remark)) {
                    matchRecord.setRemark("【%s】没有找到账单配置，转换标准账单失败，原因：【%s】".formatted(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), remark));
                } else {
                    matchRecord.setRemark("【%s】没有找到账单配置，转换标准账单失败".formatted(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
                }
                matchRecord.setUpdateTime(LocalDateTime.now());
                matchRecord.cutString();
                noMatchRecordMapper.updateById(matchRecord);
                logger.info("更新转换失败记录成功：{}", matchRecord);
            }
        }
    }

    @Override
    public void deleteNoMatchRecord(Long dataId) {
        NoMatchRecord noMatchRecord = noMatchRecordMapper.selectById(dataId);
        noMatchRecord.setStatus(NoMatchRecordStatusEnum.SUCCESS.getValue());
        noMatchRecord.setDeleted(DeleteEnum.YES.getValue());
        noMatchRecord.setRemark(" ");
        noMatchRecordMapper.update(noMatchRecord);
    }

    @Override
    public void updateSourceStatus(String tableNamePrefix, String billMonth, String dataId) {
        String tableName = "%s%s".formatted(tableNamePrefix, billMonth);
        // 标记原始账单已经转换成功
        String sql = "update `%s` set `consume` = 1 where id = '%s'".formatted(tableName, dataId);
        try {
            noMatchRecordMapper.getDataBySql(sql);
        } catch (Exception ignored) {
        }
    }
}
